use multi_platform_crawler_lib::validation::{
    Validator, ValidationRule, ValidationError, ValidationPatterns,
    sanitize_string, sanitize_filename, QueryValue
};

#[cfg(test)]
mod validation_tests {
    use super::*;

    #[test]
    fn test_required_validation() {
        let validator = Validator::new()
            .add_rule("name", ValidationRule::required());

        // Test required field with None
        assert!(validator.validate_string("name", None).is_err());
        
        // Test required field with empty string
        assert!(validator.validate_string("name", Some("")).is_err());
        
        // Test required field with valid value
        assert!(validator.validate_string("name", Some("John")).is_ok());
    }

    #[test]
    fn test_length_validation() {
        let validator = Validator::new()
            .add_rule("username", ValidationRule::length(3, 20));

        // Test too short
        assert!(validator.validate_string("username", Some("ab")).is_err());
        
        // Test valid length
        assert!(validator.validate_string("username", Some("john")).is_ok());
        
        // Test too long
        let long_name = "a".repeat(25);
        assert!(validator.validate_string("username", Some(&long_name)).is_err());
    }

    #[test]
    fn test_pattern_validation() {
        let email_pattern = ValidationPatterns::email().unwrap();
        let validator = Validator::new()
            .add_rule("email", ValidationRule::pattern(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap());

        // Test invalid email
        assert!(validator.validate_string("email", Some("invalid-email")).is_err());
        
        // Test valid email
        assert!(validator.validate_string("email", Some("test@example.com")).is_ok());
    }

    #[test]
    fn test_number_validation() {
        let validator = Validator::new()
            .add_rule("age", ValidationRule::range(0, 120));

        // Test negative number
        assert!(validator.validate_number("age", Some(-1)).is_err());
        
        // Test valid number
        assert!(validator.validate_number("age", Some(25)).is_ok());
        
        // Test too large number
        assert!(validator.validate_number("age", Some(150)).is_err());
    }

    #[test]
    fn test_combined_validation_rules() {
        let validator = Validator::new()
            .add_rule("username", 
                ValidationRule {
                    required: true,
                    min_length: Some(3),
                    max_length: Some(20),
                    pattern: Some(ValidationPatterns::username().unwrap()),
                    ..Default::default()
                }
            );

        // Test all validations pass
        assert!(validator.validate_string("username", Some("john_doe")).is_ok());
        
        // Test required validation fails
        assert!(validator.validate_string("username", None).is_err());
        
        // Test length validation fails
        assert!(validator.validate_string("username", Some("ab")).is_err());
        
        // Test pattern validation fails
        assert!(validator.validate_string("username", Some("john@doe")).is_err());
    }

    #[test]
    fn test_dangerous_characters_validation() {
        let validator = Validator::new()
            .add_rule("input", ValidationRule::required());

        // Test dangerous characters
        assert!(validator.validate_string("input", Some("<script>")).is_err());
        assert!(validator.validate_string("input", Some("test>")).is_err());
        assert!(validator.validate_string("input", Some("test&")).is_err());
        
        // Test safe input
        assert!(validator.validate_string("input", Some("safe input")).is_ok());
    }

    #[test]
    fn test_validation_patterns() {
        // Test email pattern
        let email_pattern = ValidationPatterns::email().unwrap();
        assert!(email_pattern.is_match("test@example.com"));
        assert!(!email_pattern.is_match("invalid-email"));

        // Test username pattern
        let username_pattern = ValidationPatterns::username().unwrap();
        assert!(username_pattern.is_match("john_doe"));
        assert!(username_pattern.is_match("user123"));
        assert!(!username_pattern.is_match("user@name"));
        assert!(!username_pattern.is_match("ab")); // too short

        // Test filename pattern
        let filename_pattern = ValidationPatterns::filename().unwrap();
        assert!(filename_pattern.is_match("document.txt"));
        assert!(filename_pattern.is_match("my-file_v2.pdf"));
        assert!(!filename_pattern.is_match("file<name>.txt"));

        // Test path pattern
        let path_pattern = ValidationPatterns::path().unwrap();
        assert!(path_pattern.is_match("/home/user/documents"));
        assert!(path_pattern.is_match("./relative/path"));
        assert!(!path_pattern.is_match("/path/with<invalid>chars"));
    }

    #[test]
    fn test_sanitize_string() {
        assert_eq!(
            sanitize_string("<script>alert('xss')</script>"),
            "&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;"
        );
        
        assert_eq!(
            sanitize_string("Hello & \"World\""),
            "Hello &amp; &quot;World&quot;"
        );
        
        assert_eq!(
            sanitize_string("Normal text"),
            "Normal text"
        );
    }

    #[test]
    fn test_sanitize_filename() {
        assert_eq!(
            sanitize_filename("file<>name.txt"),
            "filename.txt"
        );
        
        assert_eq!(
            sanitize_filename("my-file_v2.pdf"),
            "my-file_v2.pdf"
        );
        
        assert_eq!(
            sanitize_filename("file|with:invalid*chars?.txt"),
            "filewithinvalidchars.txt"
        );
    }

    #[test]
    fn test_validation_error_types() {
        let validator = Validator::new()
            .add_rule("field", ValidationRule::required());

        match validator.validate_string("field", None) {
            Err(ValidationError::Required { field }) => {
                assert_eq!(field, "field");
            }
            _ => panic!("Expected Required error"),
        }

        let validator = Validator::new()
            .add_rule("field", ValidationRule::length(5, 10));

        match validator.validate_string("field", Some("abc")) {
            Err(ValidationError::Length { field, min, max }) => {
                assert_eq!(field, "field");
                assert_eq!(min, 5);
                assert_eq!(max, 10);
            }
            _ => panic!("Expected Length error"),
        }
    }

    #[test]
    fn test_validation_rule_builders() {
        // Test required rule
        let rule = ValidationRule::required();
        assert!(rule.required);
        assert!(rule.min_length.is_none());

        // Test length rule
        let rule = ValidationRule::length(3, 20);
        assert_eq!(rule.min_length, Some(3));
        assert_eq!(rule.max_length, Some(20));

        // Test pattern rule
        let rule = ValidationRule::pattern(r"^\d+$").unwrap();
        assert!(rule.pattern.is_some());

        // Test range rule
        let rule = ValidationRule::range(0, 100);
        assert_eq!(rule.min_value, Some(0));
        assert_eq!(rule.max_value, Some(100));
    }

    #[test]
    fn test_multiple_field_validation() {
        let validator = Validator::new()
            .add_rule("username", ValidationRule::required())
            .add_rule("email", ValidationRule::pattern(r"^[^@]+@[^@]+\.[^@]+$").unwrap())
            .add_rule("age", ValidationRule::range(0, 120));

        // Test all fields valid
        assert!(validator.validate_string("username", Some("john")).is_ok());
        assert!(validator.validate_string("email", Some("john@example.com")).is_ok());
        assert!(validator.validate_number("age", Some(25)).is_ok());

        // Test individual field failures
        assert!(validator.validate_string("username", None).is_err());
        assert!(validator.validate_string("email", Some("invalid")).is_err());
        assert!(validator.validate_number("age", Some(-1)).is_err());
    }

    #[test]
    fn test_optional_field_validation() {
        let validator = Validator::new()
            .add_rule("optional_field", ValidationRule::length(3, 10));

        // Optional field with None should pass (not required)
        assert!(validator.validate_string("optional_field", None).is_ok());
        
        // Optional field with valid value should pass
        assert!(validator.validate_string("optional_field", Some("valid")).is_ok());
        
        // Optional field with invalid value should fail
        assert!(validator.validate_string("optional_field", Some("ab")).is_err());
    }
}
